package com.base.dao;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;

import com.base.utils.BeanToSqlutils;
import com.base.utils.ReflectUtils;

/**
 * 将常用sql查询方式放入该模板中，以后所有dao层类都继承它
 * @param <T>
 * @param <PK>
 */
public class DataTemplateDaoImpl<T, PK> implements TemplateDao<T, PK> {

	@Resource(name = "data_namedParameterJdbcTemplate")
	protected NamedParameterJdbcTemplate jt;

	// 实体类类型(由构造方法自动赋值)
	private Class<T> entityClass;

	// 构造方法，根据实例类自动获取实体类类型
	@SuppressWarnings("unchecked")
	public DataTemplateDaoImpl() {
		this.entityClass = null;
		Class<?> c = getClass();
		Type t = c.getGenericSuperclass();
		if (t instanceof ParameterizedType) {
			Type[] p = ((ParameterizedType) t).getActualTypeArguments();
			this.entityClass = (Class<T>) p[0];
		}
	}

	/**
	 * 根据主键获取实体。如果没有相应的实体，返回 null。
	 * @param id
	 * @return
	 */
	@Override
	public T get(PK id) {
		String sql = "select * from " + BeanToSqlutils.getTableName(entityClass)
				+ " where [id]=:id";
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("id", id);
		return jt.queryForObject(sql, params,
				ParameterizedBeanPropertyRowMapper.newInstance(entityClass));
	}

	/**
	 * 更新实体
	 * @param entity
	 */
	@Override
	public void update(T entity) {
		String sql = BeanToSqlutils.getUpdateSql(null, entityClass)
				+ " where "+BeanToSqlutils.equalCondition("id", null);
		jt.update(sql, new BeanPropertySqlParameterSource(entity));
	}

	/**
	 * 根据属性名更新特定的字段,properties和columns字段长度要求一致
	 * @param project     要更新的实体
	 * @param properties  属性字段 区分大小小
	 */
	public void updateByBeanProperty(T entity, List<String> properties) {
		StringBuilder sb = new StringBuilder("update ");
		sb.append(BeanToSqlutils.getTableName(entityClass));
		sb.append(" set ");
		for (int i = 0; i < properties.size(); i++) {
			sb.append(BeanToSqlutils.assembleCondition(properties.get(i).toLowerCase(),properties.get(i).toLowerCase(), null, "=:")+ ",");
		}
		sb.deleteCharAt(sb.length() - 1);
		sb.append(" where "+BeanToSqlutils.equalCondition("id", null));
		jt.update(sb.toString(), new BeanPropertySqlParameterSource(entity));
	}

	/**
	 * 更新去掉properties中属性的其余属性
	 * @param project   要更新的实体
	 * @param properties 不更新的属性字段 区分大小小
	 */
	public void updateExceptProperty(T entity, List<String> properties) {
		String sql = BeanToSqlutils.getUpdateSqlStr(null, entityClass,
				properties) + " where "+BeanToSqlutils.equalCondition("id", null);
		jt.update(sql, new BeanPropertySqlParameterSource(entity));
	}

	/**
	 * 保存实体返回id(主键自增的时候使用)
	 * @param entity
	 * @return
	 */
	@SuppressWarnings("unchecked")
	@Override
	public PK saveReturnId(T entity) {
		KeyHolder holder = new GeneratedKeyHolder();
		jt.update(BeanToSqlutils.getInsertSql(entityClass, true),
				new BeanPropertySqlParameterSource(entity), holder);
		Number key = holder.getKey().intValue();
		ReflectUtils.setFieldValue(entity, "id", key);
		return (PK) key;
	}

	/**
	 * 保存实体(主键用户指定时使用)
	 * @param entity
	 */
	@Override
	public void save(T entity) {
		jt.update(BeanToSqlutils.getInsertSql(entityClass, true),
				new BeanPropertySqlParameterSource(entity));
	}

	/**
	 * 根据ID删除实体
	 */
	@Override
	public void delete(PK id) {
		String sql = "delete from " + BeanToSqlutils.getTableName(entityClass)
				+ " where "+BeanToSqlutils.equalCondition("id", null);
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("id", id);
		jt.update(sql, params);
	}

	@Override
	public List<T> findAll() {
		String sql = "select * from " + BeanToSqlutils.getTableName(entityClass);
		return jt.query(sql,
				ParameterizedBeanPropertyRowMapper.newInstance(entityClass));
	}
	
	
	public Integer saveReturnIntId(T entity) {
		KeyHolder holder = new GeneratedKeyHolder();
		jt.update(BeanToSqlutils.getInsertSql(entityClass, true),
				new BeanPropertySqlParameterSource(entity), holder);
		int key =  holder.getKey().intValue();
		ReflectUtils.setFieldValue(entity, "id", key);
		return  key;
	}
	
	public Long saveReturnLongId(T entity) {
		KeyHolder holder = new GeneratedKeyHolder();
		jt.update(BeanToSqlutils.getInsertSql(entityClass, true),
				new BeanPropertySqlParameterSource(entity), holder);
		long key =  holder.getKey().intValue();
		ReflectUtils.setFieldValue(entity, "id", key);
		return  key;
	}

}
